Skip to content

Commit d8e6f7c

Browse files
committed
remove documents without revs after user deletion
1 parent f6ad507 commit d8e6f7c

File tree

3 files changed

+59
-1
lines changed

3 files changed

+59
-1
lines changed

kitsune/wiki/handlers.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,21 @@ def on_user_deletion(self, user: User) -> None:
5050
based_on=None
5151
)
5252

53+
# Translations with one or more revisions whose based-on matches one of the
54+
# revisions that will be deleted, will lose those revisions via cascade deletion.
55+
# Gather these translations, so we can check later if they no longer have any
56+
# revisions, and so need to be deleted themselves.
57+
translations_affected = list(
58+
Document.objects.filter(
59+
parent__isnull=False, revisions__based_on__in=revs_to_delete
60+
).values_list("id", flat=True)
61+
)
62+
5363
Document.objects.filter(
5464
revisions__creator=user,
5565
current_revision__isnull=True,
5666
).exclude(revisions__creator__in=User.objects.exclude(id=user.id)).delete()
5767
revs_to_delete.delete()
68+
69+
# Delete any translations that no longer have any revisions due to cascade deletions.
70+
Document.objects.filter(revisions__isnull=True, id__in=translations_affected).delete()

kitsune/wiki/models.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -965,7 +965,9 @@ def latest_revision(excluded_rev, constraint):
965965
except IndexError:
966966
return None
967967

968-
Revision.objects.filter(based_on=self).update(based_on=None)
968+
# Block cascade deletions, via "based_on", of revisions of parent documents.
969+
Revision.objects.filter(document__parent__isnull=True, based_on=self).update(based_on=None)
970+
969971
document = self.document
970972

971973
# If the current_revision is being deleted, try to update it to the

kitsune/wiki/tests/test_handlers.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,3 +236,46 @@ def test_revision_based_on_deletion(self):
236236
rev3 = Revision.objects.filter(id=rev3_id).first()
237237
self.assertIsNotNone(rev3, "The approved revision should not be deleted")
238238
self.assertEqual(rev3.based_on, rev2)
239+
240+
def test_revision_based_on_deletion_with_translation(self):
241+
"""
242+
Test the handling of a revision's "based_on" field, when it references a revision
243+
created by a user that is deleted, within the context of a translation.
244+
"""
245+
doc = DocumentFactory()
246+
rev1 = RevisionFactory(document=doc, creator=self.user)
247+
rev2 = ApprovedRevisionFactory(document=doc, based_on=rev1)
248+
249+
de_doc = DocumentFactory(parent=doc, locale="de")
250+
de_rev = RevisionFactory(document=de_doc, based_on=rev1)
251+
252+
it_doc = DocumentFactory(parent=doc, locale="it")
253+
it_rev1 = RevisionFactory(document=it_doc, based_on=rev1)
254+
it_rev2 = RevisionFactory(document=it_doc, based_on=rev2)
255+
256+
doc_id = doc.id
257+
rev1_id = rev1.id
258+
rev2_id = rev2.id
259+
de_doc_id = de_doc.id
260+
de_rev_id = de_rev.id
261+
it_doc_id = it_doc.id
262+
it_rev1_id = it_rev1.id
263+
it_rev2_id = it_rev2.id
264+
265+
self.listener.on_user_deletion(self.user)
266+
267+
# Ensure that the based-on handling of revisions within parent-less
268+
# documents is correct.
269+
self.assertTrue(Document.objects.filter(id=doc_id).exists())
270+
self.assertFalse(Revision.objects.filter(id=rev1_id).exists())
271+
self.assertTrue(Revision.objects.filter(id=rev2_id, based_on=None).exists())
272+
273+
# Ensure that the un-approved translated revision is cascade deleted,
274+
# and also that its document, if it no longer has any revisions, is
275+
# also deleted.
276+
self.assertFalse(Revision.objects.filter(id=de_rev_id).exists())
277+
self.assertFalse(Document.objects.filter(id=de_doc_id).exists())
278+
279+
self.assertFalse(Revision.objects.filter(id=it_rev1_id).exists())
280+
self.assertTrue(Revision.objects.filter(id=it_rev2_id, based_on=rev2).exists())
281+
self.assertTrue(Document.objects.filter(id=it_doc_id).exists())

0 commit comments

Comments
 (0)